﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using umbraco.cms.businesslogic.web;
using System.Text;
using umbraco.cms.businesslogic.propertytype;
using System.Transactions;
using System.Data.SqlClient;
using umbraco;

namespace TheOutfield.UmbExt.DocTypeExtensions.Dialogs
{
    public partial class ExtractMasterDocType : System.Web.UI.Page
    {
        public DocumentType DocType { get; set; }
        public DocumentType MasterDocType { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            // TODO: Don't allow extracting if aleady has a master doc type

            var docTypeId = Convert.ToInt32("0" + Request.QueryString["id"]);
            if (docTypeId > 0)
            {
                DocType = new DocumentType(docTypeId);
                if (DocType != null)
                {
                    var masterDocTypeId = DocType.MasterContentType;
                    if (masterDocTypeId > 0)
                    {
                        // THROW EXCEPTION
                    }
                }
            }

            if (!IsPostBack)
            {
                InitView();
            }
        }

        protected void mvExtractMasterDocType_ActiveViewChanged(object sender, EventArgs e)
        {
            var activeView = mvExtractMasterDocType.GetActiveView();

            if (activeView == vwMapDocTypeProperties)
                BindMapDocTypePropertiesView();

            if (activeView == vwConfirm)
                BindConfirmView();
        }


        protected void btnEnterMasterDocTypeName_Click(object sender, EventArgs e)
        {
            // TODO: Check master doc type name?
            mvExtractMasterDocType.SetActiveView(vwMapDocTypeProperties);
        }

        protected void btnMapDocTypeProperties_Click(object sender, EventArgs e)
        {
            mvExtractMasterDocType.SetActiveView(vwConfirm);
        }

        protected void btnConfirm_Click(object sender, EventArgs e)
        {
            DoExtract();
        }

        protected void InitView()
        {
            var err = "";

            if (DocType == null || DocType.Id == 0)
                err = "Invalid Document Type ID";

            if (err != "")
            {
                lblErrorMessage.Text = err;
                mvExtractMasterDocType.SetActiveView(vwError);
            }
            else
            {
                mvExtractMasterDocType.SetActiveView(vwEnterMasterDocTypeName);
            }
        }

        protected void BindMapDocTypePropertiesView()
        {
            var properties = DocType.PropertyTypes;

            cblProperties.DataSource = properties;
            cblProperties.DataTextField = "Name";
            cblProperties.DataValueField = "Id";
            cblProperties.DataBind();
        }

        protected void BindConfirmView()
        {
            lblConfirmMessage.Text = string.Format("Extract master doc type '{0}' from '{1}'",
                txtMasterDocTypeName.Text,
                DocType.Text);

            lblConfirmMessage.Text += "<br />";

            foreach (ListItem item in cblProperties.Items)
            {
                if(item.Selected)
                {
                    lblConfirmMessage.Text += string.Format("<br />Extract property '{0}'",
                        item.Text);
                }
            }
        }

        protected void DoExtract()
        {
            // Create the master doc type
            // NB: Easier to use the API, but it does mean it's not held within transaction, so will have to cleanup
            // later if transaction fails
            MasterDocType = DocumentType.MakeNew(umbraco.BusinessLogic.User.GetUser(0), txtMasterDocTypeName.Text);
            MasterDocType.Save();

            // Map properties
            var sb = new StringBuilder();

            if (MasterDocType != null && MasterDocType.Id > 0)
            {
                foreach (ListItem item in cblProperties.Items)
                {
                    if (item.Selected)
                    {
                        sb.AppendFormat(@"UPDATE	cmsPropertyType
                                        SET		contentTypeId = {1}
                                        WHERE	id = {2} AND
                                                contentTypeId = {0}                                        
                                        ",
                            DocType.Id,
                            MasterDocType.Id,
                            item.Value);
                    }
                }

                // Swap master doc type
                sb.AppendFormat(@"UPDATE	cmsContentType
                    SET		masterContentType = {1}
                    WHERE	nodeId in (
			                    SELECT  ct.nodeId
			                    FROM	cmsContentType as ct
					                    inner join cmsContent as c on c.contentType = ct.nodeId
					                    inner join umbracoNode as n on n.id = c.nodeId
			                    WHERE	n.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972' and
					                    ct.nodeId = {0}
		                    )
                    ",
                    DocType.Id,
                    MasterDocType.Id);

                // Execute SQL
                try
                {
                    using (TransactionScope scope = new TransactionScope())
                    {
                        using (SqlConnection conn = new SqlConnection(GlobalSettings.DbDSN))
                        {
                            conn.Open();

                            var sql = sb.ToString();
                            SqlCommand cmd = new SqlCommand(sql, conn);
                            cmd.ExecuteNonQuery();
                        }
                        scope.Complete();
                    }
                }
                catch (TransactionAbortedException ex)
                {
                    DoCleanup();

                    lblErrorMessage.Text = "Unable to extract master doc type.<br /><br />An error occured causing the transaction to fail:<br />" + ex.Message;
                    mvExtractMasterDocType.SetActiveView(vwError);
                    return;

                }
                catch (Exception ex)
                {
                    DoCleanup();

                    lblErrorMessage.Text = "Unable to extract master doc type.<br /><br />An error occured causing the transaction to fail:<br />" + ex.Message;
                    mvExtractMasterDocType.SetActiveView(vwError);
                    return;
                }

                lblSuccessMessage.Text = string.Format("Successfully extracted master doc type '{0}' from '{1}'.",
                    MasterDocType.Text,
                    DocType.Text);

                mvExtractMasterDocType.SetActiveView(vwSuccess);
            }
            else
            {
                DoCleanup();

                lblErrorMessage.Text = "Unable to extract master doc type.<br /><br />Unable to create master doc type.<br />";
                mvExtractMasterDocType.SetActiveView(vwError);
                return;
            }
        }

        protected void DoCleanup()
        {
            if (MasterDocType != null && MasterDocType.Id > 0)
                MasterDocType.delete();
        }
    }
}